<template>
    <el-dialog v-model="dialogVisible" :title="dialogTitle" :width="dialogWidth" :top="dialogTop"
        custom-class="file-preview-dialog" destroy-on-close @closed="onDialogClosed" :fullscreen="isFullscreen"
        :modal="true" :lock-scroll="true" :show-close="true" append-to-body :draggable="true" :resizable="true">
        <template #header>
            <div class="dialog-header">
                <span class="el-dialog__title">{{ dialogTitle }}</span>
                <div class="header-actions">
                    <!-- 打印按钮 -->
                    <el-button v-if="canPrint" :icon="Printer" @click="handlePrint" title="打印 (Ctrl+P)" circle text />
                    <el-button v-if="isTextFile(fileData)" :icon="CopyDocument" @click="handleCopyText" title="复制内容"
                        circle text />
                    <el-button v-if="isTextFile(fileData) || isPdfFile(fileData)" :icon="wordWrap ? Sort : DCaret"
                        @click="toggleWordWrap" :title="wordWrap ? '关闭自动换行' : '开启自动换行'" circle text />
                    <el-button :icon="FullScreenIcon" @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏'"
                        circle text />
                </div>
            </div>
        </template>

        <div class="preview-content" v-loading="loading" element-loading-text="正在加载文件...">
            <PreviewError v-if="error" :message="error" :debug-url="lastAttemptedUrl" @retry="retryLoad" />

            <template v-else-if="fileData">
                <ImagePreview v-if="isImageFile(fileData)" :file="fileData" :url="previewUrl" @loaded="onImageLoad"
                    @error="onImageError" @zoom="imageZoomed = !imageZoomed" />

                <VideoPreview v-else-if="isVideoFile(fileData)" :file="fileData" :url="previewUrl" @loaded="onVideoLoad"
                    @error="onVideoError" />

                <PdfPreview v-else-if="isPdfFile(fileData)" :file="fileData" :url="previewUrl"
                    @supported="pdfSupported = true" @unsupported="pdfSupported = false" @error="onPdfError" />

                <TextPreview v-else-if="isTextFile(fileData)" :content="textContent" :loading="textLoading"
                    :error="textError" :word-wrap="wordWrap" @retry="loadTextContent" />

                <OfficePreview v-else-if="isOfficeFile(fileData)" :file="fileData" :url="previewUrl"
                    @error="officeLoadError = true" @load="officeLoadError = false" />

                <UnsupportedPreview v-else :file="fileData" @download="$emit('download', fileData)" />
            </template>

            <div v-else class="preview-empty">无法加载预览内容</div>
        </div>

        <template #footer>
            <div class="dialog-footer">
                <el-button @click="dialogVisible = false">关闭</el-button>
                <el-button type="primary" @click="$emit('download', fileData)">下载</el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup>
import { ref, watch, computed, nextTick, onMounted, onUnmounted } from "vue";
import { ElDialog, ElMessage } from "element-plus";
import {
    FullScreen,
    Refresh,
    CopyDocument,
    Sort,
    DCaret,
    Printer,
} from "@element-plus/icons-vue";
import PreviewError from "../PreviewFile/PreviewError.vue";
import ImagePreview from "../PreviewFile/ImagePreview.vue";
import VideoPreview from "../PreviewFile/VideoPreview.vue";
import PdfPreview from "../PreviewFile/PdfPreview.vue";
import TextPreview from "../PreviewFile/TextPreview.vue";
import OfficePreview from "../PreviewFile/OfficePreview.vue";
import UnsupportedPreview from "../PreviewFile/UnsupportedPreview.vue";

// --- Props and Emits ---
const props = defineProps({
    visible: {
        type: Boolean,
        default: false,
    },
    fileData: {
        type: Object,
        default: null,
        validator: (value) => {
            if (value === null) return true;
            if (typeof value !== "object" || Array.isArray(value)) return false;
            return (
                (typeof value.id === "string" ||
                    typeof value.url === "string") &&
                typeof value.name === "string"
            );
        },
    },
});

const emit = defineEmits(["update:visible", "close", "download"]);

// --- Reactive State ---
const dialogVisible = computed({
    get: () => props.visible,
    set: (val) => emit("update:visible", val),
});

const loading = ref(false);
const error = ref("");
const textContent = ref("");
const textLoading = ref(false);
const textError = ref("");
const wordWrap = ref(true);
const isFullscreen = ref(false);
const imageInfo = ref(null);
const videoInfo = ref(null);
const pdfSupported = ref(true);
const imageZoomed = ref(false);
const officeLoadError = ref(false);
const lastAttemptedUrl = ref("");

// --- Computed Properties ---
const FullScreenIcon = computed(() =>
    isFullscreen.value ? Refresh : FullScreen
);

const dialogTitle = computed(() => {
    if (!props.fileData) return "文件预览";
    return `预览: ${props.fileData.name || "未知文件"}`;
});

const previewUrl = computed(() => {
    let url = "";
    if (!props.fileData) return url;

    if (props.fileData.id) {
        const baseUrl = window.location.origin;
        try {
            url = new URL(
                `/api/files/${encodeURIComponent(props.fileData.id)}/preview`,
                baseUrl
            ).href;
        } catch (e) {
            console.error("URL construction failed:", e);
            error.value = "预览地址生成失败";
        }
    } else if (props.fileData.url) {
        url = props.fileData.url;
    }
    lastAttemptedUrl.value = url;
    return url;
});

const dialogWidth = computed(() => {
    if (isFullscreen.value) return "100%";
    if (!props.fileData) return "80%";

    const screenWidth = window.innerWidth;

    if (isImageFile(props.fileData) || isVideoFile(props.fileData)) {
        return Math.min(0.9 * screenWidth, 1200) + "px";
    }
    if (isPdfFile(props.fileData) || isTextFile(props.fileData)) {
        return Math.min(0.85 * screenWidth, 1000) + "px";
    }
    return Math.min(0.5 * screenWidth, 600) + "px";
});

const dialogTop = computed(() => {
    if (isFullscreen.value) return "0";
    const screenHeight = window.innerHeight;
    return Math.max(0.05 * screenHeight, 20) + "px";
});

// --- 健壮性与打印功能增强 ---
const getFileExtension = (fileName) => {
    if (!fileName || typeof fileName !== "string") return "";
    const parts = fileName.split(".");
    if (parts.length < 2) return "";
    const ext = parts.pop();
    return ext ? ext.toLowerCase() : "";
};

const imageExts = new Set([
    "jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "tiff", "ico",
]);
const isImageFile = (file) => {
    if (!file) return false;
    const ext = getFileExtension(file.name);
    return imageExts.has(ext);
};

const videoExts = new Set([
    "mp4", "avi", "mkv", "mov", "wmv", "flv", "webm", "m4v", "3gp", "ogv",
]);
const isVideoFile = (file) => {
    if (!file) return false;
    const ext = getFileExtension(file.name);
    return videoExts.has(ext);
};

const isPdfFile = (file) => {
    if (!file) return false;
    const ext = getFileExtension(file.name);
    return ext === "pdf";
};

const textExts = new Set([
    "txt", "md", "log", "js", "ts", "jsx", "tsx", "java", "py", "cpp", "c", "cs", "go", "rb", "php",
    "html", "css", "scss", "less", "xml", "json", "yaml", "yml", "csv", "sql", "vue", "sh", "bat", "ps1",
]);
const isTextFile = (file) => {
    if (!file) return false;
    const ext = getFileExtension(file.name);
    return textExts.has(ext);
};

const officeExts = new Set(["doc", "docx", "xls", "xlsx", "ppt", "pptx"]);
const isOfficeFile = (file) => {
    if (!file) return false;
    const ext = getFileExtension(file.name);
    return officeExts.has(ext);
};

const handleError = (err, context = "") => {
    console.error(`${context}:`, err);
    let message = "发生未知错误";
    if (err.message) {
        if (err.message.includes("Failed to fetch")) {
            message = "网络请求失败，请检查连接或稍后重试。";
        } else if (err.message.includes("404")) {
            message = "文件未找到 (404)。";
        } else if (err.message.includes("403")) {
            message = "无权限访问该文件 (403)。";
        } else {
            message = err.message;
        }
    }
    error.value = message;
};

const loadFile = async () => {
    if (!props.fileData) {
        error.value = "未提供文件信息";
        return;
    }

    error.value = "";
    officeLoadError.value = false;
    pdfSupported.value = true;

    if (!previewUrl.value) {
        if (!error.value) error.value = "无法生成预览地址";
        return;
    }

    loading.value = true;

    try {
        if (isTextFile(props.fileData)) {
            await loadTextContent();
        }
    } catch (err) {
        handleError(err, "加载文件");
    } finally {
        loading.value = false;
    }
};

const loadTextContent = async () => {
    if (!props.fileData || !isTextFile(props.fileData) || !previewUrl.value) {
        textError.value = "无法加载文本内容";
        return;
    }

    textLoading.value = true;
    textError.value = "";
    textContent.value = "";

    try {
        const response = await fetch(previewUrl.value);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        const text = await response.text();
        textContent.value = text;
    } catch (err) {
        textError.value = err.message || "加载文件内容时出错";
        handleError(err, "加载文本内容");
    } finally {
        textLoading.value = false;
    }
};

// --- 优化后的打印功能 ---
const canPrint = computed(() => {
    if (!props.fileData) return false;
    return (
        isTextFile(props.fileData) ||
        isPdfFile(props.fileData) ||
        isImageFile(props.fileData)
    );
});

const handlePrint = () => {
    if (!canPrint.value) {
        ElMessage.warning("当前文件类型不支持打印");
        return;
    }

    const printWindow = window.open("", "_blank");
    if (!printWindow) {
        ElMessage.error("无法打开打印窗口，请检查浏览器设置");
        return;
    }

    printWindow.document.write('<html><head><title>打印预览</title>');
    printWindow.document.write("<style>");
    printWindow.document.write(`
        body { font-family: Arial, sans-serif; margin: 20px; }
        pre { white-space: pre-wrap; word-wrap: break-word; }
        img { max-width: 100%; height: auto; }
    `);
    printWindow.document.write("</style></head><body>");

    if (isTextFile(props.fileData)) {
        printWindow.document.write(`<pre>${textContent.value}</pre>`);
        printWindow.document.write("</body></html>");
        printWindow.document.close();
        printWindow.focus();
        printWindow.print();
    } else if (isPdfFile(props.fileData)) {
        // 直接导航到 PDF URL 并尝试打印
        printWindow.location.href = previewUrl.value;
        printWindow.onload = () => {
            printWindow.focus();
            printWindow.print();
        };
        // 延迟再次尝试打印，以防 onload 未触发或 PDF 查看器初始化慢
        setTimeout(() => {
            printWindow.focus();
            printWindow.print();
        }, 1500); // 增加到1.5秒以提高兼容性

    } else if (isImageFile(props.fileData)) {
        printWindow.document.write(
            `<img src="${previewUrl.value}" alt="${props.fileData.name}" onload="window.print()">`
        );
        printWindow.document.write("</body></html>");
        printWindow.document.close();
    }
};

// --- Event Handlers ---
const retryLoad = () => {
    error.value = "";
    officeLoadError.value = false;
    loadFile();
};

const onImageLoad = (info) => {
    imageInfo.value = info;
};

const onImageError = (err) => {
    handleError(err, "图片加载");
};

const onVideoLoad = (info) => {
    videoInfo.value = info;
};

const onVideoError = (err) => {
    handleError(err, "视频加载");
};

const onPdfError = (err) => {
    pdfSupported.value = false;
    handleError(err, "PDF加载");
};

const toggleWordWrap = () => {
    wordWrap.value = !wordWrap.value;
};

const toggleFullscreen = () => {
    isFullscreen.value = !isFullscreen.value;
};

const handleCopyText = async () => {
    if (!textContent.value) {
        ElMessage.info("没有内容可复制");
        return;
    }
    try {
        await navigator.clipboard.writeText(textContent.value);
        ElMessage.success("内容已复制到剪贴板");
    } catch (err) {
        handleError(err, "复制文本");
        ElMessage.error("复制失败");
    }
};

// --- Lifecycle Hooks ---
watch(
    dialogVisible,
    (newVal) => {
        if (newVal) {
            nextTick(() => {
                loadFile();
            });
        }
    },
    { immediate: true }
);

watch(
    () => props.fileData,
    (newFile, oldFile) => {
        if (newFile !== oldFile && dialogVisible.value) {
            loadFile();
        }
    },
    { deep: true }
);

const handleKeydown = (event) => {
    if (event.key === "Escape" && dialogVisible.value) {
        dialogVisible.value = false;
    }
    if (
        (event.key === "F11" || (event.key === "Enter" && event.ctrlKey)) &&
        dialogVisible.value
    ) {
        event.preventDefault();
        toggleFullscreen();
    }
    if (
        (event.ctrlKey || event.metaKey) &&
        event.key === "p" &&
        dialogVisible.value &&
        canPrint.value
    ) {
        event.preventDefault();
        handlePrint();
    }
};

onMounted(() => {
    document.addEventListener("keydown", handleKeydown);
});

onUnmounted(() => {
    document.removeEventListener("keydown", handleKeydown);
});

const onDialogClosed = () => {
    textContent.value = "";
    textLoading.value = false;
    textError.value = "";
    imageInfo.value = null;
    videoInfo.value = null;
    error.value = "";
    isFullscreen.value = false;
    wordWrap.value = true;
    imageZoomed.value = false;
    officeLoadError.value = false;
    lastAttemptedUrl.value = "";
    emit("close");
};
</script>

<style scoped>
.file-preview-dialog {
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
}

:deep(.el-dialog__header) {
    padding: 15px 20px;
    border-bottom: 1px solid #eee;
}

.dialog-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.header-actions {
    display: flex;
    gap: 10px;
}

:deep(.el-dialog__body) {
    padding: 0;
    height: 85vh;
    display: flex;
    flex-direction: column;
}

.file-preview-dialog.is-fullscreen :deep(.el-dialog__body) {
    height: 100vh !important;
}

.preview-content {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
    padding: 10px;
    box-sizing: border-box;
    overflow: auto;
    flex-direction: column;
}

.preview-empty {
    color: #909399;
    text-align: center;
    padding: 40px 20px;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.dialog-footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 15px 20px;
    border-top: 1px solid #eee;
}

@media (max-width: 768px) {
    .file-preview-dialog:not(.is-fullscreen) {
        width: 95% !important;
        top: 2vh !important;
    }

    :deep(.el-dialog__body) {
        height: 85vh;
    }

    .header-actions {
        gap: 5px;
    }
}
</style>
